import { message } from "antd";
import to from "await-to-js";
import dayjs from "dayjs";
import _ from "lodash";
import Papa from "papaparse";

import {
  ParamDataPayload,
  ParamQueryInput,
  ParamType,
  ProcessStatus,
} from "../api-server/types";
import { Scheduler } from "./schedule";
import {
  HandleRemotePathsParmas,
  JobParams,
  WorkSpaceParams,
  NoExist,
} from "./store/models";
import { workerDispatch } from "./workerQueue";

import { getContent } from "~/plugins/api-server";
import { getDataByKey, addData } from "~/utils/DataCache";
import eventBus from "~/utils/event";

/**
 * worker-job 数据已经准备好，从前后端缓存取数据
 * @param jobParams
 * @returns
 */
export const job = (jobParams: JobParams): Promise<any> => {
  return new Promise(async (res, rej) => {
    const file = `${jobParams.flight}_${jobParams.param}`;
    try {
      const exist = jobParams.has(jobParams.flight, jobParams.param);
      //---前端存在缓存---
      if (exist) {
        await getDataByIndexDB(jobParams, file);
        return res({ file, status: "done" });
      } else {
        //---前端不存在缓存---
        await getDataByInterface(jobParams, file);
        return res({ file, status: "done" });
      }
    } catch (error) {
      console.log("get data error", error);
      return rej({ file, status: "error", error });
    }
  });
};

/**
 * 处理后端数据准备进度，已经ready的数据加入queue
 * @param handleRemotePathsParmas
 * @returns
 */
export const handleRemoteProgress = (
  handleRemotePathsParmas: HandleRemotePathsParmas
) => {
  const result = {
    allProcessComplete: false,
  };
  const complete: ParamDataPayload[] = _.filter(
    handleRemotePathsParmas.data,
    (d: ParamDataPayload) => {
      return (
        (d.dataSource && d.processStatus === ProcessStatus.Completed) ||
        d.processStatus === ProcessStatus.Failed
      );
    }
  ) as ParamDataPayload[];
  const inProgress = _.filter(
    handleRemotePathsParmas.data,
    (d: ParamDataPayload) => {
      return (
        d.processStatus === ProcessStatus.Pending ||
        d.processStatus === ProcessStatus.InProgress
      );
    }
  );

  if (inProgress.length === 0) {
    result.allProcessComplete = true;
  }
  if (complete.length > 0) {
    _.forEach(complete, (c: ParamDataPayload) => {
      if (c.processStatus == ProcessStatus.Failed) {
        console.log(c);
        message.error(`${c.flightId}_${c.metric.name}获取数据失败！`);
      } else {
        const file = `${c.flightId}_${c.metric.name}`;
        if (!_.includes(Scheduler.alreadyQueue, file)) {
          const job_params: JobParams = {
            flight: c.flightId,
            param: c.metric.name,
            paramType: ParamType.Field,
            processStatus: c.processStatus,
            dataSource: c.dataSource,
            has: handleRemotePathsParmas.has,
            add: handleRemotePathsParmas.add,
          };
          workerDispatch.push(job_params);
          Scheduler.alreadyQueue.push(file);
        }
      }
    });
  }
  return result;
};

/**
 * 对数据进行采样
 * @param data
 * @param param
 * @returns
 */
export const setupSampling = (data: any[], param: string) => {
  let result = [];
  let step = 1;
  if (10000 <= data.length && data.length <= 100000) {
    step = 10;
  } else if (100000 <= data.length && data.length <= 1000000) {
    step = 100;
  }
  result = _.filter(data, (d, i) => {
    return d && d[param] !== "" && i % step === 0;
  });

  return result;
};

/**
 * 从前端indexed数据库获取数据
 * @param jobParams
 * @param file
 */
export const getDataByIndexDB = async (
  jobParams: JobParams,
  file: string
): Promise<void> => {
  const [err, data]: any = await to(
    getDataByKey(Scheduler.db, "flights", file)
  );
  if (err) {
    message.error(`本地缓存${file}获取csv数据失败！`);
    console.log("get indexed db data error", err);
    Scheduler.datas[jobParams.param] = _.unionBy(
      _.concat(Scheduler.datas[jobParams.param], []),
      "systime"
    );
  } else {
    Scheduler.datas[jobParams.param] = _.unionBy(
      _.concat(
        Scheduler.datas[jobParams.param],
        data?.value ?? []
        //   setupSampling(data?.value ?? [], jobParams.param)
      ),
      "systime"
    );
  }
};

/**
 * 从后端获取csv数据
 * @param jobParams
 * @param file
 */
export const getDataByInterface = async (
  jobParams: JobParams,
  file: string
): Promise<void> => {
  let [err, data]: [any, any] = [null, []];
  if (jobParams.processStatus === ProcessStatus.Completed) {
    const getRemoteFile = (dataSource: string) => {
      return new Promise((res, rej) => {
        try {
          Papa.parse(getContent().files_apiServer + dataSource, {
            // worker: true,
            download: true,
            header: true,
            transformHeader(header: string, index: number) {
              console.log("header", header);
              if (header == "r") {
                return jobParams.param;
              }
              return header;
            },
            complete(results) {
              // if (
              //   results?.data[results?.data.length - 1] &&
              //   (results?.data[results?.data.length - 1] as any)[
              //     jobParams.param
              //   ] == ""
              // ) {
              //   (results?.data[results?.data.length - 1] as any)[
              //     jobParams.param
              //   ] = "";
              // }
              return res(results?.data ?? []);
            },
            error(error) {
              console.log("read file error:", error);
              return rej("error");
            },
          });
        } catch (error) {
          console.log("get remote file error:", error);
          return rej("error");
        }
      });
    };
    [err, data] = await to(getRemoteFile(jobParams.dataSource));
    if (err) {
      message.error(`${file}获取csv数据失败！`);
      data = [];
    } else {
      addData(Scheduler.db, "flights", { file, key: file, value: data });
      jobParams.add({
        name: file,
        flight: jobParams.flight,
        param: jobParams.param,
        createdAt: dayjs().format(),
        updateAt: dayjs().format(),
      });
    }
  } else {
    message.error(`${file}数据准备失败！`);
  }
  Scheduler.datas[jobParams.param] = _.uniqBy(
    _.concat(
      Scheduler.datas[jobParams.param],
      data
      // setupSampling(data, jobParams.param)
    ),
    "systime"
  );
};

/**
 * 前端已有的缓存直接加入队列，返回前端不存在的
 * @param workSpaceParams
 * @returns
 */

export const handleFlightsParams = (workSpaceParams: WorkSpaceParams) => {
  let noExistFlightIds: string[] = [],
    noExistParams: ParamQueryInput[] = [];

  _.forEach(workSpaceParams.params, (param: ParamQueryInput) => {
    Scheduler.datas[param.expr] = [];

    _.forEach(workSpaceParams.flightIds, (flightId) => {
      if (workSpaceParams.has(flightId, param.expr)) {
        const job_params: JobParams = {
          flight: flightId,
          param: param.expr,
          paramType: param.type,
          processStatus: ProcessStatus.Completed,
          dataSource: "",
          has: workSpaceParams.has,
          add: workSpaceParams.add,
        };
        workerDispatch.push(job_params);
        Scheduler.alreadyQueue.push(`${flightId}_${param.expr}`);
      } else {
        noExistFlightIds.push(flightId);
        noExistParams.push(param);
      }
    });
  });
  noExistFlightIds = _.uniq(noExistFlightIds);
  noExistParams = _.uniq(noExistParams);
  return { noExistFlightIds, noExistParams };
};

/**
 * 获取后端数据准备进度
 * @param workSpaceParams
 * @param noExist
 */
export const getRemoteFilePath = async (
  workSpaceParams: WorkSpaceParams,
  noExist: NoExist
) => {
  return new Promise(async (resolve, reject) => {
    const [err, result]: [any, { [key: string]: any } | undefined] = await to(
      workSpaceParams.loadResult({
        flightIds: noExist.noExistFlightIds,
        params: noExist.noExistParams,
      })
    );
    if (err) {
      resolve({ status: "error" });
    } else {
      const paramsData = result?.data?.paramsData ?? [];
      const handleRemotePathsParmas = {
        data: paramsData,
        has: workSpaceParams.has,
        add: workSpaceParams.add,
      };
      const { allProcessComplete } = handleRemoteProgress(
        handleRemotePathsParmas
      );
      resolve({ allProcessComplete });
    }
  });
};

export const TimeoutGetData = async (
  workSpaceParams: WorkSpaceParams,
  noExist: NoExist
) => {
  if (noExist.noExistFlightIds.length > 0 && noExist.noExistParams.length > 0) {
    Scheduler.startTime = new Date().getTime();

    // --- 轮询接口 ---

    const setTimeoutGetData = () => {
      getRemoteFilePath(workSpaceParams, noExist).then((res: any) => {
        if (res.status && res.status == "error") {
          // --- 返回error清除定时轮询 ---
          message.error("获取飞行数据失败！");
          stopSetTimeout();
        } else if (res.allProcessComplete) {
          //   全部完成，清除定时轮询
          stopSetTimeout(false);
        } else {
          // --- 超时清除定时轮询 ---
          const currentTime = new Date().getTime();
          if (currentTime - Scheduler.startTime >= Scheduler.timeout) {
            message.error("获取飞行数据超时！");
            stopSetTimeout();
          } else {
            Scheduler.timer = setTimeout(setTimeoutGetData, 2000);
          }
        }
      });
    };

    setTimeoutGetData();
  }
};

const stopSetTimeout = (isStopQueue: boolean = true) => {
  if (Scheduler.timer) {
    clearTimeout(Scheduler.timer);
    Scheduler.timer = null;
  }
  //没有队列任务，直接返回
  if (isStopQueue && Scheduler.alreadyQueue.length == 0) {
    eventBus.emit(`queueComplete`);
  }
};
